<?php

require_once(dirname(__FILE__).'/resourcepage_extension.php');

/**
 * Base class for 'push' extensions. 
 * 
 * Push extensions add individual items to resource pages where 'placeholders'
 * have been positioned. 
 * 
 * To implement a push extension you need to create a folder myextension inside 
 * resourcepage/extensions, and create a file there called myextension.php that
 * includes a class resourcepage_myextension which extends this base class.
 * 
 * In order to make a 'default' extension (i.e. if you aren't going to override
 * anything in this class except the basics) you need to:
 * 1. In resourcepage_myextension, override get_database_version to return an 
 *    initial version number. 
 * 2. Create tables.xml (in your extension folder) that defines your tables;
 *    you must include a &lt;maintable> at least as this is used to store details
 *    of your placeholders.
 * 3. Create edit.xml (in your extension folder) that defines your settings page,
 *    if required. (If not required, an edit link won't appear.)
 * 4. Create moodle/lang/en_utf8/resourcepage_myextension.php, which must include the
 *    following, for a placeholder called 'apple':
 *    placeholder_apple_title - Title displayed to editing users in menu etc)
 *    placeholder_apple_description - Description displayed under each placeholder 
 *      by default
 *    The language file can also include field_XX strings which will be used to
 *      provide labels for edit.xml controls.
 * 
 * @copyright &copy; 2006 The Open University
 * @author s.marshall@open.ac.uk
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 * @package resourcepage
 */
abstract class resourcepage_extension_push extends resourcepage_extension {
    
    /**
     * Constructs extension object.
     * @param object $resourcepage Resourcepage module object
     */ 
    function __construct(&$resourcepage) {
        parent::__construct($resourcepage);
    }
    
    /**
     * Displays the HTML content of the form used to edit instances
     * of this extension.
     * @param bool $create If true, create rather than update 
     * @param object $course Course object
     * @param int $placeholderitemid Placeholder item ID
     * @param object $cm Course-module object
     * @param array $parameters Optional name=>value array of extra hidden values for form
     */    
    public function show_edit_form($course,$placeholderitemid,$cm,$parameters=array()) {        
        global $CFG;
        if (file_exists($CFG->dirroot.'/mod/resourcepage/extensions/'.$this->get_name().'/edit_form.php')) {
            require_once($CFG->dirroot.'/mod/resourcepage/extensions/'.$this->get_name().'/edit_form.php');
            $extclass = 'ext_'.$this->get_name().'_edit_form';
            $editform = new $extclass('saveextension.php');

            // Get extension fields
            $fields_ext = array();
            if($placeholderitemid != 0) {
                // Get row from extension's table as array
                $fields_ext = (array)$this->get_maintable_record($placeholderitemid);
            }

            // Append input parameters + default fields
            $fields_form = array_merge($fields_ext, $parameters);
            $fields_form['extension'] = $this->get_name();
            $fields_form['coursemodule'] = $cm->id;

            // Set form default values
            $editform->set_data($fields_form);

            // display form
            $editform->display();
        } else {
            error('No formslib form description file found for this activity.');
        }
    }
    
    /**
     * Either adds or updates the instance depending on whether it exists or not.
     * @param int $placeholderitemid Placeholder item ID
     * @param object $content Object containing form fields from the setup page.
     */
    public function addupdate_instance($placeholderitemid,$content) {
        if($this->get_maintable_record($placeholderitemid)) {
            $this->update_instance($content);
        } else {
            $this->add_instance($content);
        }
    }
    
    /**
     * Returns the record from the extension's main table corresponding to given details.
     * @param int $placeholderitemid Placeholder item ID
     * @return mixed Object of colname->value for all fields in main table, or false if there
     *   is no record yet.
     */
    protected function get_maintable_record($placeholderitemid) {
        $rs=$this->resourcepage->do_sql(
            'SELECT * FROM '.$this->get_maintable_name().' WHERE placeholderitemid='.$placeholderitemid);
        if($rs->EOF) {
            return false;
        }
        return $this->convert_maintable_record($rs);
    }
    
    /**
     * Converts fields from a recordset (current row) into a record object.
     * @throws Exception if ADODB call fails 
     */
    private function convert_maintable_record(&$rs) {
        
        $objectversion=new stdClass;
        foreach($rs->fields as $key=>$value) {
            if(preg_match('/[^0-9]/',$key)) {
                $objectversion->{strtolower($key)}=$value;
            }
        }
        return $objectversion;
    }
    
    /**
     * Can be overridden to set form values prior to displaying the settings
     * page. Default reads a row from the main table.
     * @param bool $create If true, create rather than update 
     * @param object $course Course object (not used unless by overrides)
     * @param string $placeholder Placeholder ID string
     * @param object &$form Form data object
     * @return maintable record id 
     */
    protected function init_edit_form($course,$placeholderitemid,&$form) {

        // Define maintable record id
        $id = 0;

        // Get row from extension's table as array, if it has one yet
        $record=$this->get_maintable_record($placeholderitemid);
        if($record) {
            // Add each one to the form
            foreach((array)$record as $name=>$value) {
                $form->{$name}=$value;
            }

            // Set maintable record id
            $id = $record->id;
        }
    
        // Note: This method could've just assigned the get_record
        // results to the $form, but I did it this way in case 
        // at some later point $form might have predefined values
        // that we don't want to throw away.

        // Return maintable record id
        return $id;
    }
    
    /**
     * Called to create an instance of this extension. 
     * By default, just adds a record to the extension's main table. 
     * @param int $placeholderitemid Placeholder item ID  
     * @param string $placeholder Placeholder ID
     * @param int $courseid Course ID  
     */    
    public function add_instance($placeholderitemid,$placeholder,$courseid) {                
        $content=new stdClass;
        $content->placeholderitemid=$placeholderitemid;        
        $this->before_add_instance($content,$placeholder,$courseid);
        $this->insert_maintable_record($content);
    }
    
    private function insert_maintable_record($record) {        
        global $db;
        if (!insert_record('resourcepage_x_'.$this->get_name(), $record, false)) {
            throw new Exception('resourcepage_x_'.$this->get_name().' SQL error: '.$db->ErrorMsg());
        }
    }
    
    /**
     * Called to update settings for an instance of this extension. 
     * 
     * By default, just updates the database record. 
     * @param object $content Object containing form fields from the setup page
     */    
    public function update_instance($content) {
        if(empty($content->placeholderitemid)) {
            throw new Exception('Expecting $content->placeholderitemid to be set');
        }
        
        $this->before_update_instance($content,false);
               
        global $db;
        if (!update_record('resourcepage_x_'.$this->get_name(), $content)) {
            throw new Exception('resourcepage_x_'.$this->get_name().' SQL error: '.$db->ErrorMsg());
        }
    }
    
    /**
     * Overridable method that gets called before updating an
     * instance record. You can use this if the form fields from the setup page
     * might not match the fields that need to be added to the database.
     * @param &$content Object containing form fields from the setup page.
     * @param $isadd True if this is add, false if it's update
     */
    protected function before_update_instance(&$content,$isadd) {
    }    

    /**
     * Overridable method that gets called before adding a new instance record. 
     * You can use this to set up default values for the table entries (or you
     * can leave it to database defaults)
     * @param object &$content Object to which values can be added
     * @param string $placeholder Placeholder string
     * @param int $courseid Course ID
     */
    protected function before_add_instance(&$content,$placeholder,$courseid) {
    }    

    /**
     * Default version deletes main table data for the instance.
     */    
    public function delete_instance($placeholderitemid) {        
        if(!($record=$this->get_maintable_record($placeholderitemid))) {
            return;
        }
                   
        // Give subclass a chance to do something else
        $this->before_deleting_instance($record);
            
        // Delete entry
        $this->resourcepage->do_sql('DELETE FROM '.
            $this->get_maintable_name().' WHERE placeholderitemid='.$placeholderitemid);
                
        $this->after_deleting_instance($record);
    }
    
    /**
     * Called by before_deleting_course just before an instance is deleted.
     * 
     * Default does nothing. Override to achieve specific behaviour
     * while retaining the standard delete that's done for you. 
     * @param object $record Object of database fields 
     */    
    protected function before_deleting_instance($record) {
    }
    /**
     * Called by before_deleting_course just after an instance is deleted.
     * 
     * Default does nothing. Override to achieve specific behaviour
     * while retaining the standard delete that's done for you. 
     * @param object $record Object of database fields 
     */    
    protected function after_deleting_instance($record) {
    }
    
    /**
     * Must return a list of placeholders provided by this extension.
     * @return array An array of placeholder ID strings (lower-case
     *   alphanumeric only)
     */
    protected abstract function get_placeholders();
    
    /**
     * Obtains the name of a placeholder for display to staff.
     * Default version obtains it from the appropriate language file
     * as placeholder_thisplaceholder_title.
     * @param string $placeholder Placeholder ID
     * @param int $courseid Course ID
     * @return string Full name of placeholder  
     */
    public function get_placeholder_title($placeholder,$placeholderitemid) {
        return get_string('placeholder_'.$placeholder.'_title','resourcepage_'.$this->get_name());
    }

    /**
     * Obtains the description of a placeholder for display to staff.
     * Default version obtains it from the appropriate language file
     * as placeholder_thisplaceholder_description.
     * @param string $placeholder Placeholder ID
     * @param int $placeholderitemid Individual placeholder item ID (not used in default)
     * @return string Full name of placeholder  
     */
    public function get_placeholder_description($placeholder,$placeholderitemid) {
        return get_string('placeholder_'.$placeholder.'_description','resourcepage_'.$this->get_name());
    }
    
    
    /** 
     * Adds placeholder details to database after installing
     * DB tables.
     */
    public function install() {        
        parent::install();
        
        $placeholders=$this->get_placeholders();
        foreach($placeholders as $placeholder) {
            $this->resourcepage->add_placeholder($placeholder,$this->get_name());
        }                
    }
    
    /**
     * Removes placeholder details from database before uninstalling
     * DB tables.
     */
    public function uninstall() {
        $placeholders=$this->get_placeholders();
        foreach($placeholders as $placeholder) {
            $this->resourcepage->delete_placeholder($placeholder);
        }
                        
        parent::uninstall();
    }    
    
    /**
     * Write backup XML for one container of this extension. Default
     * version just saves all the fields from the main table. 
     * @param xml_backup &$backup Backup handler
     * @param module_resourcepage &$rp Resourcepage object
     * @param string $placeholder Identifies the placeholder type
     * @param int $itemid Item ID for the actual placeholder instance
     */
    public function backup(&$backup,&$rp,$placeholder,$itemid) {
        $backup->tag_start('PUSHEXTENSION');
        $record=(array)$this->get_maintable_record($itemid);
        foreach($record as $name=>$value) {
            if($name=='placeholderitemid') {
                continue;
            }
            $backup->tag_full_notnull(strtoupper($name),$value);
        }
        $backup->tag_end('PUSHEXTENSION');
    }
    /**
     * Restores from backup XML for one container of this extension. 
     * Default version restores fields from main table. 
     * @param object $restoresettings Moodle object with restore settings
     * @param module_resourcepage &$rp Resourcepage object
     * @param int $placeholderitemid Identifies the newly-created placeholder
     * @param array $xml Dodgy Moodle parsed XML format 
     */
    public function restore($restoresettings,&$rp,$placeholderitemid,$xml) {
        // Fill record
        $record=new stdClass;
        $record->placeholderitemid=$placeholderitemid;
        foreach($xml['PUSHEXTENSION'][0]['#'] as $field=>$data) {
            $record->{strtolower($field)}=$data[0]['#'];
        }
        
        // Insert it
        $this->insert_maintable_record($record);        
    }
    
}


?>
